/*
 * @Author: 0x9DEFA478
 * @Date: 2022-01-23 15:31:56
 * @LastEditTime: 2022-07-25 19:57:39
 * @LastEditors: 0x9DEFA478
 * @Description: 
 * QQ:2652450237
 * ============================================================================================================================================
 * 
 * 
 * 
 *                                                                                               ************      ****************************
 *                                                                                             ************      ****************************  
 *                                                                                           ************      ****************************    
 *                                                                                         ************      ****************************      
 *                                                                                       ************      ************                        
 *                                                                                     ************      ************                          
 *                                                                                   ************      ************                            
 *                                                                                 ************      ************                              
 *                                                                               ************      ************                                
 *                                                                             ************      ************                                  
 *                                                                           ************      ************                                    
 *                                                                         ************      ************                                      
 *                                                                       ************      ************                                        
 *                                                                     ************      ************                                          
 *                                                                   ************      ************                                            
 *                                                                 ************      ************                                              
 *                                                               ************      ************                                                
 *                                                             ************      ************                                                  
 *                                                           ************      ************                                                    
 *                                                         ************      ************                                                      
 *                                                       ************      ************                                                        
 *                                                     ************      ************                                                          
 *                                                   ************      ************                                                            
 *                                                 ************      ************                                                              
 *                                               ************      ************                                                                
 *                                             ************      ************                                                                  
 *                                           ************      ************                                                                    
 *                                         ************      ************                                                                      
 *                                       ************      ************                                                                        
 *                                     ************      ************                                                                          
 *                                   ************      ************                                                                            
 *                                 ************      ************                                                                              
 *                               ************      ************                                                                                
 *                             ************      ************                                                                                  
 *                           ************      ************                                                                                    
 *                         ************      ************                                                                                      
 *       ****************************      ************                                                                                        
 *     ****************************      ************                                                                                          
 *   ****************************      ************                                                                                            
 * ****************************      ************                                                                                              
 * 
 * 
 * 
 * ============================================================================================================================================
 * 
 */
#include "./H_NES_Console.h"




static void ArrayCopy(void* dst,void* src,int Size){
  while(Size>0){
    Size--;
    ((Hbyte*)dst)[Size]=((Hbyte*)src)[Size];
  }
}




//预退出调用
void H_NES_Console_PreExit(H_NES_Console* Console){
  H_NES_Message msg;

  Console->LL_Function.ExitCallback(Console->LL_Function.v);

  msg.FunctionIndex=vH_NES_Message_FunctionIndex_Stop;
  msg.v=NULL;
  Console->LL_Function.Thread.MessageSned(Console->MessageQueue.Ack,&msg);
}

#define cToByteArray(_in_v) ((Hbyte*)&_in_v)
#define oCopyToArray(_in_dst,_in_v,_in_Size) ArrayCopy(&_in_dst,cToByteArray(_in_v),_in_Size)
#define oCopyToValue(_in_src,_in_v,_in_Size) ArrayCopy(cToByteArray(_in_v),&_in_src,_in_Size)

void H_NES_Console_GetProgress(H_NES_Console* Console,void* Progress){
  Hbyte* p;
  int i;

  p=Progress;
  i=0;




  //CPU
  oCopyToArray(p[i],Console->CPU.MCLK,4);i+=4;

  p[i]=Console->CPU.Register.A;i=i+1;
  p[i]=Console->CPU.Register.X;i=i+1;
  p[i]=Console->CPU.Register.Y;i=i+1;
  p[i]=Console->CPU.Register.P;i=i+1;
  p[i]=Console->CPU.Register.S;i=i+1;

  oCopyToArray(p[i],Console->CPU.Register.PC,2);i=i+2;

  p[i]=cToByteArray(Console->CPU.APU_Clock)[0];i=i+1;

  oCopyToArray(p[i],Console->CPU.Status,2);i=i+2;
  
  oCopyToArray(p[i],Console->CPU.DMA.OAMADDR,2);i=i+2;

  //APU
  oCopyToArray(p[i],Console->CPU.APU.FrameCounter.Reg_4017_CPUClock,4);i=i+4;
  //Pulse1
  oCopyToArray(p[i],Console->CPU.APU.Channel.Pulse1.Timer.Period_Cnt,4);i=i+4;

  p[i]=Console->CPU.APU.Channel.Pulse1.Reg_4000;i=i+1;

  oCopyToArray(p[i],Console->CPU.APU.Channel.Pulse1.Sweep.TargetTimerPeriod,2);i=i+2;

  oCopyToArray(p[i],Console->CPU.APU.Channel.Pulse1.Sweep.Reg_4001_PCnt,2);i=i+2;
  
  p[i]=Console->CPU.APU.Channel.Pulse1.Envelope.DividerValue;i=i+1;
  p[i]=Console->CPU.APU.Channel.Pulse1.Envelope.StartFlag;i=i+1;
  p[i]=Console->CPU.APU.Channel.Pulse1.Envelope.DecayLevel;i=i+1;

  p[i]=Console->CPU.APU.Channel.Pulse1.Sequencer.Step;i=i+1;

  oCopyToArray(p[i],Console->CPU.APU.Channel.Pulse1.LengthCounter.Period_Cnt,2);i=i+2;
  //Pulse2
  oCopyToArray(p[i],Console->CPU.APU.Channel.Pulse2.Timer.Period_Cnt,4);i=i+4;

  p[i]=Console->CPU.APU.Channel.Pulse2.Reg_4004;i=i+1;

  oCopyToArray(p[i],Console->CPU.APU.Channel.Pulse2.Sweep.TargetTimerPeriod,2);i=i+2;

  oCopyToArray(p[i],Console->CPU.APU.Channel.Pulse2.Sweep.Reg_4005_PCnt,2);i=i+2;
  
  p[i]=Console->CPU.APU.Channel.Pulse2.Envelope.DividerValue;i=i+1;
  p[i]=Console->CPU.APU.Channel.Pulse2.Envelope.StartFlag;i=i+1;
  p[i]=Console->CPU.APU.Channel.Pulse2.Envelope.DecayLevel;i=i+1;

  p[i]=Console->CPU.APU.Channel.Pulse2.Sequencer.Step;i=i+1;

  oCopyToArray(p[i],Console->CPU.APU.Channel.Pulse2.LengthCounter.Period_Cnt,2);i=i+2;
  //Triangle
  oCopyToArray(p[i],Console->CPU.APU.Channel.Triangle.Timer.Period_Cnt,4);i=i+4;

  oCopyToArray(p[i],Console->CPU.APU.Channel.Triangle.LinerCounter.Reg_4008_Cnt,2);i=i+2;

  oCopyToArray(p[i],Console->CPU.APU.Channel.Triangle.LengthCounter.Period_Cnt,2);i=i+2;

  p[i]=Console->CPU.APU.Channel.Triangle.Output;i=i+1;
  //Noise
  oCopyToArray(p[i],Console->CPU.APU.Channel.Noise.Timer.Period_Cnt,4);i=i+4;

  p[i]=Console->CPU.APU.Channel.Noise.Reg_400C;i=i+1;
  p[i]=Console->CPU.APU.Channel.Noise.ModeFlag;i=i+1;

  p[i]=Console->CPU.APU.Channel.Noise.Envelope.DividerValue;i=i+1;
  p[i]=Console->CPU.APU.Channel.Noise.Envelope.StartFlag;i=i+1;
  p[i]=Console->CPU.APU.Channel.Noise.Envelope.DecayLevel;i=i+1;

  oCopyToArray(p[i],Console->CPU.APU.Channel.Noise.ShiftRegister,2);i=i+2;

  oCopyToArray(p[i],Console->CPU.APU.Channel.Noise.LengthCounter.Period_Cnt,2);i=i+2;
  //DMC
  oCopyToArray(p[i],Console->CPU.APU.Channel.DMC.Timer.Period_Cnt,4);i=i+4;

  p[i]=Console->CPU.APU.Channel.DMC.Reg_4010;i=i+1;
  
  oCopyToArray(p[i],Console->CPU.APU.Channel.DMC.Reader.Address,2);i=i+2;
  oCopyToArray(p[i],Console->CPU.APU.Channel.DMC.Reader.NumOfLastByte,2);i=i+2;
  oCopyToArray(p[i],Console->CPU.APU.Channel.DMC.Reader.Period_Address,2);i=i+2;
  oCopyToArray(p[i],Console->CPU.APU.Channel.DMC.Reader.Period_NumOfLastByte,2);i=i+2;

  p[i]=Console->CPU.APU.Channel.DMC.Shifter.NumOfLastBit;i=i+1;
  p[i]=Console->CPU.APU.Channel.DMC.Shifter.Value;i=i+1;

  p[i]=Console->CPU.APU.Channel.DMC.MultFlag;i=i+1;
  p[i]=Console->CPU.APU.Channel.DMC.OutputLevel;i=i+1;

  p[i]=Console->CPU.APU.Status.Reg_4015_W;i=i+1;

  //PPU
  p[i]=(Hbyte)(((Husize)(Console->PPU.NameTable[0]-(Hbyte*)Console->PPU.VRAM))/1024U);i=i+1;
  p[i]=(Hbyte)(((Husize)(Console->PPU.NameTable[1]-(Hbyte*)Console->PPU.VRAM))/1024U);i=i+1;
  p[i]=(Hbyte)(((Husize)(Console->PPU.NameTable[2]-(Hbyte*)Console->PPU.VRAM))/1024U);i=i+1;
  p[i]=(Hbyte)(((Husize)(Console->PPU.NameTable[3]-(Hbyte*)Console->PPU.VRAM))/1024U);i=i+1;
  
  p[i]=Console->PPU.Register.Register[0];i=i+1;
  p[i]=Console->PPU.Register.Register[1];i=i+1;
  p[i]=Console->PPU.Register.Register[2];i=i+1;
  p[i]=Console->PPU.Register.Register[3];i=i+1;
  oCopyToArray(p[i],Console->PPU.Register.Internal.v,2);i=i+2;
  oCopyToArray(p[i],Console->PPU.Register.Internal.t,2);i=i+2;
  p[i]=Console->PPU.Register.Internal.x;i=i+1;
  p[i]=Console->PPU.Register.Internal.w;i=i+1;
  if(Console->PPU.Register.Internal.IsAddXY==0){
    p[i]=0x00U;
  }else{
    p[i]=0xFFU;
  }
  i=i+1;
  p[i]=Console->PPU.Register.PPUDATA.ReadBuffer;i=i+1;

  oCopyToArray(p[i],Console->PPU.Palettes[0],32);i=i+32;
  oCopyToArray(p[i],Console->PPU.OAM[0],256);i=i+256;

  p[i]=Console->PPU.VRAM_ScreenType;i=i+1;

  p[i]=Console->StandardController.Reg_4016_W;i=i+1;

  if(i!=vH_NES_Console_ProgressSize){
    for(;;){
      //不应该运行到此处
    }
  }
}

void H_NES_Console_LoadProgress(H_NES_Console* Console,void* Progress){
  Hbyte* p;
  int i;

  p=Progress;
  i=0;




  //CPU
  oCopyToValue(p[i],Console->CPU.MCLK,4);i+=4;

  Console->CPU.Register.A=p[i];i+=1;
  Console->CPU.Register.X=p[i];i+=1;
  Console->CPU.Register.Y=p[i];i+=1;
  Console->CPU.Register.P=p[i];i+=1;
  Console->CPU.Register.S=p[i];i+=1;

  oCopyToValue(p[i],Console->CPU.Register.PC,2);i+=2;

  cToByteArray(Console->CPU.APU_Clock)[0]=p[i];i+=1;

  oCopyToValue(p[i],Console->CPU.Status,2);i+=2;
  
  oCopyToValue(p[i],Console->CPU.DMA.OAMADDR,2);i+=2;

  //APU
  oCopyToValue(p[i],Console->CPU.APU.FrameCounter.Reg_4017_CPUClock,4);i+=4;
  //Pulse1
  oCopyToValue(p[i],Console->CPU.APU.Channel.Pulse1.Timer.Period_Cnt,4);i+=4;

  Console->CPU.APU.Channel.Pulse1.Reg_4000=p[i];i+=1;

  oCopyToValue(p[i],Console->CPU.APU.Channel.Pulse1.Sweep.TargetTimerPeriod,2);i+=2;

  oCopyToValue(p[i],Console->CPU.APU.Channel.Pulse1.Sweep.Reg_4001_PCnt,2);i+=2;
  
  Console->CPU.APU.Channel.Pulse1.Envelope.DividerValue=p[i];i+=1;
  Console->CPU.APU.Channel.Pulse1.Envelope.StartFlag=p[i];i+=1;
  Console->CPU.APU.Channel.Pulse1.Envelope.DecayLevel=p[i];i+=1;

  Console->CPU.APU.Channel.Pulse1.Sequencer.Step=p[i];i+=1;

  oCopyToValue(p[i],Console->CPU.APU.Channel.Pulse1.LengthCounter.Period_Cnt,2);i+=2;
  //Pulse2
  oCopyToValue(p[i],Console->CPU.APU.Channel.Pulse2.Timer.Period_Cnt,4);i+=4;

  Console->CPU.APU.Channel.Pulse2.Reg_4004=p[i];i+=1;

  oCopyToValue(p[i],Console->CPU.APU.Channel.Pulse2.Sweep.TargetTimerPeriod,2);i+=2;

  oCopyToValue(p[i],Console->CPU.APU.Channel.Pulse2.Sweep.Reg_4005_PCnt,2);i+=2;
  
  Console->CPU.APU.Channel.Pulse2.Envelope.DividerValue=p[i];i+=1;
  Console->CPU.APU.Channel.Pulse2.Envelope.StartFlag=p[i];i+=1;
  Console->CPU.APU.Channel.Pulse2.Envelope.DecayLevel=p[i];i+=1;

  Console->CPU.APU.Channel.Pulse2.Sequencer.Step=p[i];i+=1;

  oCopyToValue(p[i],Console->CPU.APU.Channel.Pulse2.LengthCounter.Period_Cnt,2);i+=2;
  //Triangle
  oCopyToValue(p[i],Console->CPU.APU.Channel.Triangle.Timer.Period_Cnt,4);i+=4;

  oCopyToValue(p[i],Console->CPU.APU.Channel.Triangle.LinerCounter.Reg_4008_Cnt,2);i+=2;

  oCopyToValue(p[i],Console->CPU.APU.Channel.Triangle.LengthCounter.Period_Cnt,2);i+=2;

  Console->CPU.APU.Channel.Triangle.Output=p[i];i+=1;
  //Noise
  oCopyToValue(p[i],Console->CPU.APU.Channel.Noise.Timer.Period_Cnt,4);i+=4;

  Console->CPU.APU.Channel.Noise.Reg_400C=p[i];i+=1;
  Console->CPU.APU.Channel.Noise.ModeFlag=p[i];i+=1;

  Console->CPU.APU.Channel.Noise.Envelope.DividerValue=p[i];i+=1;
  Console->CPU.APU.Channel.Noise.Envelope.StartFlag=p[i];i+=1;
  Console->CPU.APU.Channel.Noise.Envelope.DecayLevel=p[i];i+=1;

  oCopyToValue(p[i],Console->CPU.APU.Channel.Noise.ShiftRegister,2);i+=2;

  oCopyToValue(p[i],Console->CPU.APU.Channel.Noise.LengthCounter.Period_Cnt,2);i+=2;
  //DMC
  oCopyToValue(p[i],Console->CPU.APU.Channel.DMC.Timer.Period_Cnt,4);i+=4;

  Console->CPU.APU.Channel.DMC.Reg_4010=p[i];i+=1;
  
  oCopyToValue(p[i],Console->CPU.APU.Channel.DMC.Reader.Address,2);i+=2;
  oCopyToValue(p[i],Console->CPU.APU.Channel.DMC.Reader.NumOfLastByte,2);i+=2;
  oCopyToValue(p[i],Console->CPU.APU.Channel.DMC.Reader.Period_Address,2);i+=2;
  oCopyToValue(p[i],Console->CPU.APU.Channel.DMC.Reader.Period_NumOfLastByte,2);i+=2;

  Console->CPU.APU.Channel.DMC.Shifter.NumOfLastBit=p[i];i+=1;
  Console->CPU.APU.Channel.DMC.Shifter.Value=p[i];i+=1;

  Console->CPU.APU.Channel.DMC.MultFlag=p[i];i+=1;
  Console->CPU.APU.Channel.DMC.OutputLevel=p[i];i+=1;

  Console->CPU.APU.Status.Reg_4015_W=p[i];i+=1;

  //PPU
  Console->PPU.NameTable[0]=&((Hbyte*)Console->PPU.VRAM)[((Huint32)p[i])*1024U];i+=1;
  Console->PPU.NameTable[1]=&((Hbyte*)Console->PPU.VRAM)[((Huint32)p[i])*1024U];i+=1;
  Console->PPU.NameTable[2]=&((Hbyte*)Console->PPU.VRAM)[((Huint32)p[i])*1024U];i+=1;
  Console->PPU.NameTable[3]=&((Hbyte*)Console->PPU.VRAM)[((Huint32)p[i])*1024U];i+=1;
  
  Console->PPU.Register.Register[0]=p[i];i+=1;
  Console->PPU.Register.Register[1]=p[i];i+=1;
  Console->PPU.Register.Register[2]=p[i];i+=1;
  Console->PPU.Register.Register[3]=p[i];i+=1;
  oCopyToValue(p[i],Console->PPU.Register.Internal.v,2);i+=2;
  oCopyToValue(p[i],Console->PPU.Register.Internal.t,2);i+=2;
  Console->PPU.Register.Internal.x=p[i];i+=1;
  Console->PPU.Register.Internal.w=p[i];i+=1;
  if(p[i]==0x00U){
    Console->PPU.Register.Internal.IsAddXY=0;
  }else{
    Console->PPU.Register.Internal.IsAddXY=-1;
  }
  i+=1;
  Console->PPU.Register.PPUDATA.ReadBuffer=p[i];i+=1;

  oCopyToValue(p[i],Console->PPU.Palettes[0],32);i+=32;
  oCopyToValue(p[i],Console->PPU.OAM[0],256);i+=256;

  p[i]=Console->PPU.VRAM_ScreenType;i+=1;

  p[i]=Console->StandardController.Reg_4016_W;i+=1;

  if(i!=vH_NES_Console_ProgressSize){
    for(;;){
      //不应该运行到此处
    }
  }
}

#undef cToByteArray




int H_NES_Console_Command(H_NES_Console* Console,H_NES_Message* msg){
  Hbyte* p;
  Hint32* p_int32;

  //有事务处理
  switch(msg->FunctionIndex){
    case vH_NES_Message_FunctionIndex_GetProgress:
      p=msg->v;
      H_NES_Console_GetProgress(Console,p);
      p=&p[vH_NES_Console_ProgressSize];
      Console->Cartridge.Progress.Get(Console,p);
      Console->LL_Function.Thread.MessageSned(Console->MessageQueue.Ack,msg);
      break;
    case vH_NES_Message_FunctionIndex_LoadProgress:
      p=msg->v;
      H_NES_Console_LoadProgress(Console,p);
      p=&p[vH_NES_Console_ProgressSize];
      Console->Cartridge.Progress.Load(Console,p);
      Console->LL_Function.Thread.MessageSned(Console->MessageQueue.Ack,msg);
      break;
    case vH_NES_Message_FunctionIndex_Stop:
      return -1;
    case vH_NES_Message_FunctionIndex_SetVblankNMI_Delay:
      p_int32=msg->v;
      Console->CompatibilityOption.VblankNMI_Delay=p_int32[0];
      Console->LL_Function.Thread.MessageSned(Console->MessageQueue.Ack,msg);
      break;
    case vH_NES_Message_FunctionIndex_SetMMC3_CountDelay:
      p_int32=msg->v;
      Console->CompatibilityOption.MMC3_CountDelay=p_int32[0];
      Console->LL_Function.Thread.MessageSned(Console->MessageQueue.Ack,msg);
      break;
    case vH_NES_Message_FunctionIndex_Reset:
      H_NES_Cartridge_Reset(Console);
      H_NES_PPU_Reset(Console);
      H_NES_APU_Reset(Console);
      H_NES_CPU_Reset(Console);
      Console->LL_Function.Thread.MessageSned(Console->MessageQueue.Ack,msg);
      break;
    default:
      for(;;){
        //不可能的情况
      }
  }
  
  return 0;
}



